const cheerio = require('cheerio');

/**
 * 选择器配置类型定义
 * @typedef {Object} SelectorConfig
 * @property {string|Function} selector - CSS选择器或自定义函数
 * @property {string} [attr] - 要获取的属性名
 * @property {boolean} [html] - 是否获取HTML内容
 * @property {string} [method="text"] - 获取方法(text/html/attr/map)
 */

/**
 * 列表解析配置类型定义
 * @typedef {Object} ListParseOptions
 * @property {string} listSelector - 列表项选择器
 * @property {Object.<string, string|SelectorConfig>} selectors - 字段选择器配置
 */



/**
 * 序列化工具
 */
class ParserUtil {
    /**
     * 列表序列化
     * @param {string} html - 要解析的HTML字符串
     * @param {ListParseOptions} options - 解析配置
     * @returns {Array<Object>} 解析结果数组
     * @throws {Error} 当HTML为空或缺少必要参数时抛出错误
     * 
     * @example
     * // 基本用法
     * const result = ParserUtil.listParse(html, {
     *  listSelector: '.products .product-item',
     *  selectors: {
     *      name: '.name',  // 简单文本选择器
     *      price: { selector: '.price', html: true },  // 获取HTML内容
     *      image: { selector: 'img', attr: 'src' },  // 获取属性
     *      tags: { selector: '.tag', method: 'map' },  // 获取多个元素
     *      custom: { selector: itemEl => itemEl.find('.custom').data('id') }  // 自定义函数
     *  }
     * });
     */
    static listParse(html = '', options = {}) {
         if (!html) throw new Error('Parse html cannot be empty');
        if (!options.listSelector) throw new Error('List selector listSelector parameter cannot be empty');
        const $ = cheerio.load(html);
        const results = [];
        // 直接处理列表项，避免中间数组存储
        $(options.listSelector).each((i, element) => {
            const $element = $(element);
            results.push(this._parseListItem($element, options.selectors));
        });
        return results;
    }

    /**
     * 解析单个列表项
     * @param {Cheerio} $item - 列表项的Cheerio对象
     * @param {Object.<string, string|SelectorConfig>} selectors - 字段选择器配置
     * @returns {Object} 解析后的对象
     * @private
     */
    static _parseListItem($item, selectors) {
        const result = {};
        Object.entries(selectors).forEach(([key, selector]) => {
            try {
                result[key] = this._parseSelector($item, selector);
            } catch (error) {
                console.error(`Error parsing selector ${key}:`, error);
                result[key] = "";
            }
        });
        return result;
    }

    /**
     * 根据选择器配置解析内容
     * @param {Cheerio} $context - 上下文Cheerio对象
     * @param {string|SelectorConfig} selector - 选择器配置
     * @returns {string|Array<string>} 解析结果
     * @private
     */
    static _parseSelector($context, selector) {
        // 字符串选择器 - 直接获取文本
        if (typeof selector === 'string') {
            return $context.find(selector).first().text().trim();
        }
        if (typeof selector === 'object' && selector !== null) {
            // 自定义函数选择器
            if (typeof selector.selector === 'function') {
                return selector.selector($context);
            }
            const $elements = $context.find(selector.selector);
            
            // 映射多个元素
            if (selector.method === 'map') {
                return $elements.map((i, el) => {
                    return selector.attr 
                        ? $(el).attr(selector.attr) || ""
                        : $(el).text().trim();
                }).get();
            }

            // 获取单个元素
            const $element = $elements.first();
            
            if (selector.attr) {
                return $element.attr(selector.attr) || "";
            }
            
            if (selector.html) {
                return $element.html() || "";
            }
        }
        return $element.text().trim();
    }

}


module.exports = ParserUtil;